import ast
import logging
from collections import defaultdict
from typing import Dict, List, Set, Any

from 程序核心代码.ast节点.节点分析.分析器基类 import 分析器基类
from 程序核心代码.ast节点.节点定义.基础定义.ast节点基础定义 import ast节点基础模型

logger = logging.getLogger(__name__)

class 数据流分析器(分析器基类):
    """数据流分析器类，用于分析节点间的数据流动关系"""
    
    def __init__(self):
        super().__init__()
        self.定义点: Dict[str, Set[ast节点基础模型]] = defaultdict(set)  # 变量名到定义点的映射
        self.使用点: Dict[str, Set[ast节点基础模型]] = defaultdict(set)  # 变量名到使用点的映射
        self.数据流图: Dict[ast节点基础模型, Dict[str, Set[ast节点基础模型]]] = defaultdict(lambda: defaultdict(set))
        self.活跃变量: Dict[ast节点基础模型, Set[str]] = defaultdict(set)
        
    def 分析节点(self, 节点: ast节点基础模型) -> Dict[str, Any]:
        """分析指定节点的���据流关系"""
        try:
            if not self.验证节点(节点):
                return {}
                
            # 分析变量定义和使用
            self._分析变量定义使用(节点)
            
            # 分析数据流动
            self._分析数据流动(节点)
            
            # 分析活跃变量
            self._分析活跃变量(节点)
            
            # 记录分析结果
            self.分析结果[节点._节点ID] = {
                "定义变量": list(self._获取节点定义变量(节点)),
                "使用变量": list(self._获取节点使用变量(节点)),
                "数据流入": self._获取数据流入(节点),
                "数据流出": self._获取数据流出(节点),
                "活跃变量": list(self.活跃变量[节点])
            }
            
            self.标记已分析(节点)
            return self.分析结果[节点._节点ID]
            
        except Exception as e:
            self.记录分析日志(f"数据流分析失败: {str(e)}", "error")
            return {}
            
    def _分析变量定义使用(self, 节点: ast节点基础模型) -> None:
        """分析节点中的变量定义和使用情况"""
        if not hasattr(节点, '_ast节点'):
            return
            
        class 变量访问分析器(ast.NodeVisitor):
            def __init__(self, 外部实例):
                self.外部实例 = 外部实例
                self.当前节点 = 节点
                
            def visit_Name(self, ast节点):
                变量名 = ast节点.id
                if isinstance(ast节点.ctx, ast.Store):
                    self.外部实例.定义点[变量名].add(self.当前节点)
                elif isinstance(ast节点.ctx, ast.Load):
                    self.外部实例.使用点[变量名].add(self.当前节点)
                self.generic_visit(ast节点)
                
            def visit_Attribute(self, ast节点):
                if isinstance(ast节点.value, ast.Name):
                    变量名 = f"{ast节点.value.id}.{ast节点.attr}"
                    if isinstance(ast节点.ctx, ast.Store):
                        self.外部实例.定义点[变量名].add(self.当前节点)
                    elif isinstance(ast节点.ctx, ast.Load):
                        self.外部实例.使用点[变量名].add(self.当前节点)
                self.generic_visit(ast节点)
                
        分析器 = 变量访问分析器(self)
        分析器.visit(节点.ast���点)
        
    def _分析数据流动(self, 节点: ast节点基础模型) -> None:
        """分析节点间的数据流动关系"""
        # 分析通过接口的数据流动
        for 接口名, 接口 in 节点.节点接口.items():
            if 接口.方向 == "输出":
                for 目标接口 in 接口.连接列表:
                    self.数据流图[节点]["输出"].add(目标接口.节点模型)
                    self.数据流图[目标接口.节点模型]["输入"].add(节点)
                    
        # 分析通过变量的数据流动
        for 变量名 in self._获取节点定义变量(节点):
            for 使用节点 in self.使用点[变量名]:
                if 使用节点 != 节点:
                    self.数据流图[节点]["输出"].add(使用节点)
                    self.数据流图[使用节点]["输入"].add(节点)
                    
    def _分析活跃变量(self, 节点: ast节点基础模型) -> None:
        """分析节点的活跃变量"""
        # 获取当前节点使用的变量
        使用变量 = self._获取节点使用变量(节点)
        self.活跃变量[节点].update(使用变量)
        
        # 获取后继节点的活跃变量
        for 后继节点 in self.数据流图[节点]["输出"]:
            self.活跃变量[节点].update(self.活跃变量[后继节点])
            
        # 移除当前节点定义的变量
        定义变量 = self._获取节点定义变量(节点)
        self.活跃变量[节点].difference_update(定义变量)
        
    def _获取节点定义变量(self, 节点: ast节点基础模型) -> Set[str]:
        """获取节点定义的变量"""
        return {变量名 for 变量名, 定义节点集 in self.定义点.items() if 节点 in 定义节点集}
        
    def _获取节点使用变量(self, 节点: ast节点基础模型) -> Set[str]:
        """获取节点使用的变量"""
        return {变量名 for 变量名, 使用节点集 in self.使用点.items() if 节点 in 使用节点集}
        
    def _获取数据流入(self, 节点: ast节点基础模型) -> List[str]:
        """获取流入节点的数据来源"""
        return [流入节点._节点ID for 流入节点 in self.数据流图[节点]["输入"]]
        
    def _获取数据流出(self, 节点: ast节点基础模型) -> List[str]:
        """获取节点数据流向的目标"""
        return [流出节点._节点ID for 流出节点 in self.数据流图[节点]["输出"]]
        
    def 获取数据流图(self) -> Dict[str, Any]:
        """获取完整的数据流图"""
        return {
            节点._节点ID: {
                "输入": [入节点._节点ID for 入节点 in 流向["输入"]],
                "输出": [出节点._节点ID for 出节点 in 流向["输出"]]
            }
            for 节点, 流向 in self.数据流图.items()
        }
        
    def 获取变量信息(self, 变量名: str) -> Dict[str, Any]:
        """获取指定变量的定义和使用信息"""
        return {
            "定义点": [节点._节点ID for 节点 in self.定义点[变量名]],
            "使用点": [节点._节点ID for 节点 in self.使用点[变量名]]
        }
        
    def 重置(self) -> None:
        """重置分析器状态"""
        super().重置()
        self.定义点.clear()
        self.使用点.clear()
        self.数据流图.clear()
        self.活跃变量.clear()
        
    def __str__(self) -> str:
        """返回数据流分析器的字符串表示"""
        return f"数据流分析器(变量数={len(self.定义点)}, 节点数={len(self.数据流图)})" 